package com.example.codegenerator.generator;

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.builder.Controller;
import com.baomidou.mybatisplus.generator.config.builder.Entity;
import com.baomidou.mybatisplus.generator.config.builder.Mapper;
import com.baomidou.mybatisplus.generator.config.builder.Service;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.example.codegenerator.properties.EhomeAutoGeneratorProperties;
import com.example.codegenerator.constant.GlobalConstant;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;


public class EhomeAutoGenerator {
    @Autowired
    private EhomeAutoGeneratorProperties.DBConfig dbConfig;

    @Autowired
    private EhomeAutoGeneratorProperties.GlobalConfig globalConfig;

    @Autowired
    private EhomeAutoGeneratorProperties.PackageConfig packageConfig;

    @Autowired
    private EhomeAutoGeneratorProperties.StrategyConfig strategyConfig;

    private Consumer<GlobalConfig.Builder> globalConfigConsumer;

    private Consumer<PackageConfig.Builder> packageConfigConsumer;

    private Consumer<StrategyConfig.Builder> strategyConfigConsumer;

    public void globalConfig(Consumer<GlobalConfig.Builder> consumer) {
        this.globalConfigConsumer = consumer;
    }

    public void strategyConfig(Consumer<StrategyConfig.Builder> consumer) {
        this.strategyConfigConsumer = consumer;
    }

    public void packageConfig(Consumer<PackageConfig.Builder> consumer) {
        this.packageConfigConsumer = consumer;
    }

    public void execute() {
        //1.构造生成器实例
        FastAutoGenerator fastAutoGenerator = FastAutoGenerator.create(dateSourceBuilder());
        //2.添加全局配置
        fastAutoGenerator.globalConfig(this::globalConfigBuilder);
        //3.设置包配置
        fastAutoGenerator.packageConfig(this::packageConfigBuilder);
        //4.设置生成策略
        fastAutoGenerator.strategyConfig(this::strategyConfigBuilder);

        fastAutoGenerator.injectionConfig(this::injectionConfigBuilder);
        //5.设置生成模板
        fastAutoGenerator.templateConfig(this::templateConfigBuilder);
        //6设置freemark引擎生成
        fastAutoGenerator.templateEngine(new EhomeFreemarkerTemplateEngine());

        //调用自定义配置
        if(this.globalConfigConsumer!=null){
            fastAutoGenerator.globalConfig(this.globalConfigConsumer);
        }
        if(this.strategyConfigConsumer!=null){
            fastAutoGenerator.strategyConfig(this.strategyConfigConsumer);
        }
        //7.生成实例
        fastAutoGenerator.execute();
    }

    private void injectionConfigBuilder(InjectionConfig.Builder builder) {
        Map<String, String> customFile = new HashMap<>();
        customFile.put("/repository/%sRepository","/templates/repository.java.ftl");
        customFile.put("/mapping/%sMapping","/templates/mapping.java.ftl");
        builder.customFile(customFile);
    }

    /**
     * 修改模板生成文件
     *
     * @param builder
     */
    private void templateConfigBuilder(TemplateConfig.Builder builder) {
        builder.service("/templates/service.java");
        builder.serviceImpl("/templates/serviceImpl.java");
    }

    private void strategyConfigBuilder(StrategyConfig.Builder builder) {
        //生成表名
        if (strategyConfig.getTableNames() != null && strategyConfig.getTableNames().length > 0)
            builder.addInclude(strategyConfig.getTableNames());
        //字段前缀
        builder.addFieldPrefix(strategyConfig.getFieldPrefixes());
        //表前缀
        builder.addTablePrefix(strategyConfig.getTablePrefixes());
        //排除表名
        if (strategyConfig.getExcludeTableNames() != null && strategyConfig.getExcludeTableNames().length > 0)
            builder.addExclude(strategyConfig.getExcludeTableNames());
        //1.实体类生成配置
        this.createEntityBuilder(builder);
        //2.mapper xml生成配置
        this.createMapperBuilder(builder);
        //3.service 文件生成配置
        this.createServiceBuilder(builder);
        //4.controller 文件生成配置
        this.createControllerBuilder(builder);


    }

    private void createControllerBuilder(StrategyConfig.Builder strategyBuilder) {
        Controller.Builder builder = strategyBuilder.controllerBuilder();
        //开启生成@RestController控制器
        builder.enableRestStyle();
        //开启驼峰转连字符
        builder.enableHyphenStyle();
    }

    private void createServiceBuilder(StrategyConfig.Builder strategyBuilder) {
        Service.Builder builder = strategyBuilder.serviceBuilder();
        // service文件名格式
        builder.formatServiceFileName(strategyConfig.getFileNamePatternService());
        // serviceImpl文件名格式
        builder.formatServiceImplFileName(strategyConfig.getFileNamePatternServiceImpl());
    }

    private void createMapperBuilder(StrategyConfig.Builder strategyBuilder) {
        Mapper.Builder builder = strategyBuilder.mapperBuilder();
        //mapper文件名格式
        builder.formatMapperFileName(strategyConfig.getFileNamePatternMapper());
        //mapper XML文件名格式
        builder.formatXmlFileName(strategyConfig.getFileNamePatternMapperXml());
        if (BooleanUtils.isTrue(strategyConfig.getBaseResultMap())) {
            builder.enableBaseResultMap();
        }
        if (BooleanUtils.isTrue(strategyConfig.getBaseColumnList())) {
            builder.enableBaseColumnList();
        }
        // 开启mapper注解
        if (BooleanUtils.isTrue(strategyConfig.getMapperAnnotation())) {
            builder.enableMapperAnnotation();
        }
    }

    private void createEntityBuilder(StrategyConfig.Builder strategyBuilder) {
        Entity.Builder builder = strategyBuilder.entityBuilder();
        //下划线转驼峰命名
        builder.naming(NamingStrategy.underline_to_camel);
        //开启AR模式
        //builder.enableActiveRecord()
        //开始 实体类文件名格式 建议以Entity结尾
        builder.formatFileName(strategyConfig.getFileNamePatternEntity());
        //指定生成主键的id类型
//        builder.idType(IdType.NONE);
        //逻辑删除字段 基类已有继承就行
        //builder.logicDeleteColumnName(strategyConfig.getFieldLogicDelete())
        //乐观锁字段 目前没有
        //builder.versionColumnName(strategyConfig.getFieldVersion())
        //设置实体父类的全类名
        builder.superClass(strategyConfig.getSuperClassName());
        //添加需要忽略生成的表字段名 父类字段有
        builder.addIgnoreColumns(strategyConfig.getIgnoreColumns());
        if (BooleanUtils.isTrue(strategyConfig.getLombokChainModel())) {
            builder.enableChainModel();
        }
        if (BooleanUtils.isTrue(strategyConfig.getLombokModel())) {
            builder.enableLombok();
        }
        if (BooleanUtils.isTrue(strategyConfig.getColumnConstant())) {
            builder.enableColumnConstant();
        }
        // 字段注解
        if (BooleanUtils.isTrue(strategyConfig.getFieldAnnotation())) {
            builder.enableTableFieldAnnotation();
        }
    }

    private void packageConfigBuilder(PackageConfig.Builder builder) {
        //1.设置包名
        builder.parent(packageConfig.getPackageName());
        //2.controller名 // builder.moduleName("");
        builder.controller(packageConfig.getPackageController());
        //3.实体类包名
        builder.entity(packageConfig.getPackageEntity());
        //4.mapper包名
        builder.mapper(packageConfig.getPackageMapper());
        //5.mapper XML目录名
        builder.xml(packageConfig.getPackageMapperXml());
        //6.service包名
        builder.service(packageConfig.getPackageService());
        //7.serviceImpl包名
        builder.serviceImpl(packageConfig.getPackageServiceImpl());
        //8.other 包名
        builder.other("");

        Map<OutputFile, String> pathInfo = new HashMap<>();
        pathInfo.put(OutputFile.mapperXml,GlobalConstant.RESOURCES_DIR+"/mapper");
        builder.pathInfo(pathInfo);
    }

    private void globalConfigBuilder(GlobalConfig.Builder builder) {
        //1.设置作者
        builder.fileOverride().author(globalConfig.getAuthor());
        //2.设置输出路径
        String outDir = GlobalConstant.OUTPUT_DIR;
        if (StringUtils.hasText(globalConfig.getOutDir())) {
            outDir = globalConfig.getOutDir();
        }
        builder.outputDir(outDir);
        //3.设置时间类型
        DateType dateType = DateType.TIME_PACK;
        builder.dateType(dateType);
        //4.是否开启swagger
        if (BooleanUtils.isTrue(globalConfig.getSwaggerSupport())) {
            builder.enableSwagger();
        }

    }

    /**
     * 数据库连接builder
     *
     * @return
     */
    private DataSourceConfig.Builder dateSourceBuilder() {
        return new DataSourceConfig.Builder(dbConfig.getDbUrl(),
                dbConfig.getUsername(),
                dbConfig.getPassword());
    }
}
